package com.huan.dubbo.controller;

import com.huan.dubbo.service.HelloService;
import com.huan.dubbo.service.RpcRequest;
import com.huan.dubbo.service.RpcResponse;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class UserController {
    /**
     * 获取 @DubboReference(mock="")属性 这个属性作用是服务降级，设置的值如下几种：
     * 1. mock="force:return null" 无论提供者是否可用都不用取远程调用了，直接返回降级结果 null
     * 2. mock="fail:return null"  若提供者调用失败，则返回降级结果 null
     * 3. mock="true"       若提供者调用失败，则调用本地定义好的降级类；该降级类必须与业务接口同包且名称必须为 ”业务接口+Mock“
     * 4. mock="服务降级类全限类名" 若提供者调用失败，则调用指定降级类；
     */

    /**
     * 调用集群容错 doInvoke （重点核心） 集群容错机制有如下几种：
     * 1. Failover Cluster （默认）
     *
     * @DubboReference(cluster = "failover",retries = 2)
     * 失败自动切换，当出现失败，重试其它服务器。通常用于读操作，但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。
     * 2. Failfast Cluster
     * 快速失败，只发起一次调用，失败立即报错。通常用于非幂等性的写操作，比如新增记录。
     * <p>
     * 3. Failsafe Cluster
     * 失败安全，出现异常时，直接忽略。通常用于写入审计日志等操作。
     * 4. Failback Cluster
     * 失败自动恢复，后台记录失败请求，定时重发。通常用于消息通知操作。
     * 5. Forking Cluster
     * 并行调用多个服务器，只要一个成功即返回。通常用于实时性要求较高的读操作，但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数
     * 6. Broadcast Cluster
     * 广播调用所有提供者，逐个调用，任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
     * 现在广播调用中，可以通过 broadcast.fail.percent 配置节点调用失败的比例，当达到这个比例后，BroadcastClusterInvoker 将不再调用其他节点，直接抛出异常。
     * broadcast.fail.percent 取值在 0～100 范围内。默认情况下当全部调用失败后，才会抛出异常。
     * broadcast.fail.percent 只是控制的当失败后是否继续调用其他节点，并不改变结果(任意一台报错则报错)。broadcast.fail.percent 参数 在 dubbo2.7.10 及以上版本生效。
     * Broadcast Cluster 配置 broadcast.fail.percent。
     * broadcast.fail.percent=20 代表了当 20% 的节点调用失败就抛出异常，不再调用其他节点。
     * @DubboReference(cluster = "broadcast", parameters = {"broadcast.fail.percent", "20"})
     * 7. Available Cluster
     * 调用目前可用的实例（只调用一个），如果当前没有可用的实例，则抛出异常。通常用于不需要负载均衡的场景。
     * 8. Mergeable Cluster
     * 将集群中的调用结果聚合起来返回结果，通常和group一起配合使用。通过分组对结果进行聚合并返回聚合后的结果，比如菜单服务，用group区分同一接口的多种实现，现在消费方需从每种group中调用一次并返回结果，对结果进行合并之后返回，这样就可以实现聚合菜单项。
     * 9. ZoneAware Cluster
     * 多注册中心订阅的场景，注册中心集群间的负载均衡。对于多注册中心间的选址策略有如下四种:
     * 1. 指定优先级：preferred="true"注册中心的地址将被优先选择
     * <dubbo:registry address="zookeeper://127.0.0.1:2181" preferred="true" />
     * 2. 同中心优先：检查当前请求所属的区域，优先选择具有相同区域的注册中心
     * <dubbo:registry address="zookeeper://127.0.0.1:2181" zone="beijing" />
     * 3. 权重轮询：根据每个注册中心的权重分配流量
     * <dubbo:registry id="beijing" address="zookeeper://127.0.0.1:2181" weight="100" />
     * <dubbo:registry id="shanghai" address="zookeeper://127.0.0.1:2182" weight="10" />
     */
    @DubboReference(mock = "true", loadbalance = "roundrobin")
    private HelloService helloService;

    @GetMapping("/sayHello")
    public String sayHello() {
        String resutl = helloService.sayHello();
        return resutl;
    }

    @GetMapping("/sayHelloByName")
    public String sayHelloByName() {
        String resutl = helloService.sayHelloByName("张三");
        return resutl;
    }

    @GetMapping("/sayHelloRpcRequest")
    public RpcResponse sayHelloRpcRequest() {
        RpcRequest rpcRequest = new RpcRequest();
        rpcRequest.setAge(18);
        rpcRequest.setName("尼古拉斯富贵");
        List<String> list = new ArrayList<>();
        for (int i = 1; i <= 2000; i++) {
            list.add("你好"+i);
        }
        rpcRequest.setT(list);
        RpcResponse rpcResponse = helloService.sayHelloRpcRequest(rpcRequest);
        return rpcResponse;
    }
}
